HomeTabs.tsx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. "use client";
  2. import { GroupType, PrizeTypes } from "@/api/home";
  3. import Box from "@/components/Box";
  4. import CustomTabs from "@/components/Tabs";
  5. import { useRouter } from "@/i18n/routing";
  6. import { useSystemStore } from "@/stores/useSystemStore";
  7. import { getToken } from "@/utils/Cookies";
  8. import { Toast } from "antd-mobile";
  9. import clsx from "clsx";
  10. import { useTranslations } from "next-intl";
  11. import React, { FC, useState } from "react";
  12. import HomeGames from "./HomeGames";
  13. // import HomePrize from "./HomePrize";
  14. const buttonGroup: any = [
  15. // {
  16. // category_name: "sixth",
  17. // isHot: false,
  18. // url: "/freeGames",
  19. // locale: true,
  20. // lock: false,
  21. // isAnimation: true,
  22. // image: "/home/free.webp",
  23. // },
  24. // {
  25. // icon: "shipin",
  26. // category_name: "fourth",
  27. // isHot: false,
  28. // url: "/gameList?gameListFlag=10&type=1&bet_type=1&name=live",
  29. // locale: true,
  30. // lock: false,
  31. // image: "/home/live.png",
  32. // },
  33. // {
  34. // category_name: "replay",
  35. // isHot: false,
  36. // url: "/replayGames",
  37. // locale: true,
  38. // lock: false,
  39. // image: "/home/money.webp",
  40. // },
  41. // {
  42. // category_name: "history",
  43. // isHot: true,
  44. // url: "/gameList?pageType=1&name=History",
  45. // locale: true,
  46. // lock: false,
  47. // image: "/home/history.webp",
  48. // needLogin: true,
  49. // },
  50. // {
  51. // image: "/home/favorite.webp",
  52. // category_name: "Coletar",
  53. // isHot: false,
  54. // url: "/gameList?pageType=2&name=Favorite",
  55. // locale: true,
  56. // lock: false,
  57. // needLogin: true,
  58. // },
  59. ] as const;
  60. type TabItemType = (typeof buttonGroup)[number] & GroupType;
  61. const TabItem = ({
  62. item,
  63. active,
  64. onClick,
  65. }: {
  66. item: TabItemType;
  67. active?: boolean;
  68. onClick?: (item: TabItemType) => void;
  69. }) => {
  70. const t = useTranslations("ButtonGroup");
  71. const router = useRouter();
  72. const handler = (item: TabItemType) => {
  73. if (!item.locale) {
  74. onClick && onClick(item);
  75. return;
  76. }
  77. if (item.lock) {
  78. Toast.show("It is under development.");
  79. } else {
  80. if (item.needLogin && !getToken()) {
  81. router.push("/login");
  82. return;
  83. }
  84. router.push(item.url);
  85. }
  86. };
  87. const cls = clsx("pro-iconfont text-[.16rem]", item && item.icon ? `pro-${item.icon}` : "");
  88. // const cls2 = clsx("iconfont text-[.34rem]", `icon-${item.icon}`);
  89. return (
  90. <div
  91. className={clsx(
  92. "relative flex cursor-pointer items-center rounded-[.1rem] bg-[var(--main-background)] px-[.1rem] py-[.04rem]",
  93. !!active ? "text-[#fff]" : "text-[var(--textColor2)]"
  94. )}
  95. onClick={() => handler(item)}
  96. >
  97. <div className="relative z-[2] inline-block flex w-[.24rem] items-center justify-center">
  98. {!item.image && (
  99. <span
  100. className={clsx(cls, !!active ? "text-[#fff]" : "text-[var(--textColor4)]")}
  101. ></span>
  102. )}
  103. {item.image && (
  104. <img
  105. src={item.image}
  106. style={{ height: ".24rem" }}
  107. alt={item.url}
  108. className={clsx(item.isAnimation ? "animate-slow-bounce" : "")}
  109. ></img>
  110. )}
  111. </div>
  112. <div
  113. className={
  114. "relative z-[2] min-w-[0] flex-1 whitespace-nowrap px-[.02rem] text-center text-[0.1rem]"
  115. }
  116. >
  117. {item.locale ? t(item.category_name) : item.category_name}
  118. </div>
  119. {/* {item.isHot && (
  120. <img
  121. className={"absolute -top-[0.12rem] right-0 h-[0.21rem] w-[0.21rem]"}
  122. src="data:image/png;base64,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"
  123. alt=""
  124. />
  125. )} */}
  126. </div>
  127. );
  128. };
  129. interface Props {
  130. tabs: GroupType[];
  131. prize?: PrizeTypes[];
  132. }
  133. const Tabs: FC<Props> = (props) => {
  134. const { tabs, prize } = props;
  135. const router = useRouter();
  136. const { show_again_game, show_free_game } = useSystemStore((state) => {
  137. return {
  138. show_again_game: state.show_again_game,
  139. show_free_game: state.show_free_game,
  140. };
  141. });
  142. const [active, setActive] = useState<string | undefined>();
  143. const stickyRef = React.useRef<number>(0);
  144. const containerRef = React.useRef<number>(0);
  145. const handleRef = React.useRef<NodeJS.Timeout | null>(null);
  146. const newButtonGroup = buttonGroup.filter((item: any) => {
  147. if (item.url === "/freeGames" && show_free_game !== 1) {
  148. return false;
  149. }
  150. if (item.url === "/replayGames" && show_again_game !== 1) {
  151. return false;
  152. }
  153. return true;
  154. });
  155. const groupGames = React.useMemo(() => {
  156. return tabs[0]?.category;
  157. }, [tabs]);
  158. const tabData = React.useMemo(() => {
  159. return [...tabs, ...newButtonGroup].map((item, idx) => {
  160. const id = `${item.category_name}_${item.action_params}`;
  161. return {
  162. ...item,
  163. name: item.category_name,
  164. id,
  165. jump_id: item.action_params,
  166. headerRender: () => (
  167. <Box
  168. action={item.action_type}
  169. actionData={item.action_params}
  170. additional={{
  171. 6: () => {
  172. setActive(id);
  173. },
  174. 8: () => {
  175. tabClick();
  176. setActive(id);
  177. selectHandler(id);
  178. },
  179. }}
  180. pt={false}
  181. pr={false}
  182. pb={false}
  183. pl={false}
  184. >
  185. <TabItem
  186. item={item as TabItemType}
  187. active={`${id}` === active || (!active && idx === 0)}
  188. ></TabItem>
  189. </Box>
  190. ),
  191. };
  192. });
  193. // eslint-disable-next-line react-hooks/exhaustive-deps
  194. }, [tabs, active, newButtonGroup]);
  195. const tabClick = () => {
  196. if (handleRef.current) {
  197. clearTimeout(handleRef.current);
  198. handleRef.current = null;
  199. }
  200. handleRef.current = setTimeout(() => {
  201. handleRef.current = null;
  202. }, 1000);
  203. };
  204. const getTab = (id: string) => {
  205. let result = tabData.find((item: any) => {
  206. return item.id === id;
  207. });
  208. if (!result) {
  209. result = tabData[0];
  210. }
  211. return result;
  212. };
  213. React.useEffect(() => {
  214. initScroll();
  215. window.addEventListener("resize", () => {
  216. getContainerInfo();
  217. getStickyContainerInfo();
  218. });
  219. return () => {
  220. window.removeEventListener("resize", () => {
  221. getContainerInfo();
  222. getStickyContainerInfo();
  223. });
  224. };
  225. // eslint-disable-next-line react-hooks/exhaustive-deps
  226. }, []);
  227. const getStickyContainerInfo = () => {
  228. const dom = document.querySelector("#stickyContainer");
  229. if (dom) {
  230. stickyRef.current = dom.getBoundingClientRect().height;
  231. }
  232. };
  233. const getContainerInfo = () => {
  234. const dom = document.querySelector("#maincontainer");
  235. if (dom) {
  236. containerRef.current = dom.getBoundingClientRect().top;
  237. }
  238. };
  239. const initScroll = () => {
  240. const container = document.querySelector("#maincontainer");
  241. if (!container) {
  242. setTimeout(initScroll, 200);
  243. return;
  244. }
  245. container.addEventListener("scroll", doScorll);
  246. };
  247. const doScorll = () => {
  248. if (handleRef.current) return;
  249. let target = null;
  250. for (let i = 0; i < tabData.length; i++) {
  251. const element = tabData[i];
  252. if (element.action_type === 8) {
  253. const dom = document.querySelector(`#jump_${element.jump_id}`);
  254. if (dom) {
  255. const boundInfo = dom.getBoundingClientRect();
  256. if (!stickyRef.current) {
  257. getStickyContainerInfo();
  258. }
  259. if (!containerRef.current) {
  260. getContainerInfo();
  261. }
  262. if (boundInfo.top < stickyRef.current + containerRef.current + 10) {
  263. target = element;
  264. } else {
  265. break;
  266. }
  267. }
  268. }
  269. if (target) {
  270. setActive(target.id);
  271. }
  272. }
  273. // requestAnimationFrame(doScorll);
  274. };
  275. const selectHandler = (id?: string) => {
  276. if (!id) return;
  277. const toTab = getTab(id);
  278. if (toTab.action_type !== 8) return;
  279. const toDom = document.querySelector(`#jump_${toTab.jump_id}`);
  280. const container = document.querySelector("#maincontainer");
  281. if (!stickyRef.current) {
  282. getStickyContainerInfo();
  283. }
  284. if (!containerRef.current) {
  285. getContainerInfo();
  286. }
  287. if (toDom && container) {
  288. const boundInfo = toDom.getBoundingClientRect();
  289. const toScroll =
  290. container.scrollTop + boundInfo.top - containerRef.current - stickyRef.current;
  291. container.scrollTo({
  292. top: toScroll,
  293. behavior: "smooth",
  294. });
  295. }
  296. };
  297. return (
  298. <>
  299. <div
  300. className="homeTabsContainer sticky top-[0rem] z-[3] bg-[var(--primary1)] px-[.1rem] pb-[.05rem] pt-[.05rem]"
  301. id="stickyContainer"
  302. >
  303. <CustomTabs
  304. items={tabData as any}
  305. activeKey={active}
  306. onChanage={(value) => {
  307. setActive(value);
  308. }}
  309. ></CustomTabs>
  310. </div>
  311. {/* <div className="sticky top-[0rem] z-[3] bg-[var(--primary1)] px-[.1rem] pb-[.05rem] pt-[.05rem]">
  312. <Swiper
  313. slidesPerView={4.5}
  314. spaceBetween={4}
  315. // centeredSlides={true}
  316. // centeredSlidesBounds
  317. >
  318. {tabData?.map((group, index) => (
  319. <SwiperSlide key={index}>
  320. <Box
  321. action={group.action_type}
  322. actionData={group.action_params}
  323. additional={{
  324. 6: () => {
  325. setActive(index);
  326. },
  327. }}
  328. pt={false}
  329. pr={false}
  330. pb={false}
  331. pl={false}
  332. >
  333. <TabItem
  334. item={group as TabItemType}
  335. active={index === active}
  336. // onClick={(event) => selectHandler(event, index)}
  337. ></TabItem>
  338. </Box>
  339. </SwiperSlide>
  340. ))}
  341. <div className="absolute left-[0] bg-gradient-to-r from-[var(--gradient-left6)] to-[var(--gradient-right6)]">
  342. 2323
  343. </div>
  344. </Swiper>
  345. </div> */}
  346. {/* <HomePrize data={prize}></HomePrize> */}
  347. <HomeGames groupGames={groupGames} />
  348. </>
  349. );
  350. };
  351. export default Tabs;